package com.witframework.meta;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

import org.apache.commons.lang.StringUtils;
import org.hibernate.annotations.LazyToOne;
import org.hibernate.annotations.LazyToOneOption;
import org.javalid.annotations.core.JvMethod;
import org.javalid.annotations.helper.Lookup;
import org.javalid.annotations.helper.SpringLookup;
import org.javalid.annotations.validation.LovConstraint;
import org.javalid.annotations.validation.MaxLength;
import org.javalid.annotations.validation.MaxValue;
import org.javalid.annotations.validation.MinValue;
import org.javalid.annotations.validation.NotNull;

import com.witframework.core.annotations.Wit;
import com.witframework.util.Assert;

/**
 * 实体属性元数据描述类
 * @author wuxinyang
 *
 */

@Entity @Table(name="Meta_Entity_Field") @Wit(cnname = "实体字段",cnproperty="displayName")
public class MetaEntityField extends BaseMetaObject{
	
	//基本信息
	@Column(length=127)@NotNull@Wit(cnname="名称",description="属性的名称")
	private String name;

	@Wit(cnname="长度",description="列长度(默认值255)")
	private int length;

	@Wit(cnname="精度", description="列十进制精度(decimal precision)(默认值0)")
	private int precision_length;
	
	@Wit(cnname="范围", description="如果列十进制数值范围(decimal scale)可用,在此设置(默认值0)")
	private int scale;

	//校验信息constraint
	
	@Column(length=9)@Wit(cnname="最小宽度",description="字符串长度是否符合范围,属性(String)")
	private String minLength;
	
	@Column(length=9)@Wit(cnname="最大宽度",description="字符串长度是否符合范围,属性(String)")
	private String maxLength;

	
	@Column(length=19)@Wit(cnname="最小值",description="是否大于或等于最小值,属性 (以numeric或者string类型来表示一个数字)")
	private String minValue;
	
	@Column(length=19)@Wit(cnname="最大值",description="是否小于或等于最大值,属性 (以numeric或者string类型来表示一个数字)")
	private String maxValue;



	@Wit(cnname="最小值",description="值是否在最小和最大值之间(包括临界值),属性(以numeric或者string类型来表示一个数字)")
	private int rangeMin;
	
	@Wit(cnname="最大值",description="值是否在最小和最大值之间(包括临界值),属性(以numeric或者string类型来表示一个数字)")
	private int rangeMax;

	@Wit(cnname="元素最小个数",description="元素大小是否在最小和最大值之间(包括临界值)，属性为：array, collection, map")
	private int sizeMin;
	
	@Wit(cnname="元素最大个数",description="元素大小是否在最小和最大值之间(包括临界值)，属性为：array, collection, map")
	private int sizeMax;
	
	@Column(length=10)@Wit(cnname="日期类型",description="表示时间类型的数据有DATE, TIME, 和 TIMESTAMP三种精度(即单纯的日期,时间,或者两者兼备")
	private String temporal;
	
	@Column(length=1)@Wit(cnname="日期是过去的?",description="日期是否是过去时,属性为：date或calendar")
	private String past;
	
	@Column(length=1)@Wit(cnname="日期是将来的?",description=" 日期是否是将来时,属性为：date或calendar")
	private String future;
	
	@Column(length=1) @Wit(cnname="标识?", description="该列是否为实体bean的标识属性列")
	private String isIdentity="N";
	
	@Column(length=1)@Wit(cnname="唯一?",description="是否在该列上设置唯一约束")
	private String isUnique="N";
	
	@Column(length=1)@Wit(cnname="可空?", description="是否设置该列的值可以为空")
	private String isNullable="Y" ;
	@Column(length = 1)@Wit(cnname = "parent?", description = "是否是指向父的标识")
	private String isparent="N";
	
	@Column(length = 1)@Wit(cnname = "加密?", description = "是否加密，加密的界面会显示为***")
	private String isencrypted="N";
	
	@Column(length = 1)@Wit(cnname = "selection?",description = "如果是'Y',则在数据列表页面会列出，并且可以查询")
	private String isselectioncolumn="N";
	
	
	//扩展信息
	@Column(length=127)@MaxLength(length=127)	@Wit(cnname="类型名称",description="属性的类型名称")
	private String typeName;//

	@Column(length=100)@MaxLength(length=50)	@Wit(cnname="显示名称",description="属性的显示名称")
	private String displayName;

	@Column(length=60)@MaxLength(length=30) @Wit(cnname="格式",description="格式化设置，在date或calendar可直接设置format格式")
	private String format;

	@Column(length=255)@Wit(cnname="匹配表达式",description="是否与给定匹配标志的正则表达式相匹配")
	private String regularExpression;
	
	
	@Column(length=100)@MaxLength(length=50) @Wit(cnname="引用的实体的名称",description="应用的实体的名称")
	private String refEntityName;
	
	@MaxValue(10000000) @MinValue(-10000000)@Wit(cnname="顺序",description="顺序值")
	private int sortnum;

	@ManyToOne	@LazyToOne(LazyToOneOption.FALSE) @Wit(cnname="MetaEntity",description="实体名称")
	@LovConstraint (
    dynamic=true,
    lookup=@Lookup(type=Lookup.LOOKUP_SPRING_BEAN,springLookup=@SpringLookup(name="metaEntityService",method=@JvMethod(name="getAll")))
	)
	private MetaEntity metaEntity;	
	
	public String getJavaTypeName() {
		if(typeName.equals(EntityFieldType.NUMERIC))
			return EntityFieldType.getJavaTypeName(typeName,this.precision_length);
		if(this.getRefEntityName()!=null)
			return typeName;
		return EntityFieldType.getJavaTypeName(typeName);
	}
	private String getWitAnnotations(){
		String annotation=" @Wit(";
		if(getDisplayName()!=null){			
			annotation+="cnname=\""+getDisplayName()+"\"";
		}
		if(getDescription()!=null){
			if(annotation.length()>6) annotation+=",";
			annotation+="description=\""+getDescription()+"\"";
		}
		return annotation+")";
	}
	public String getFieldAnnotations(){
		String idAnnotation="";
		if(StringUtils.equals(getIsIdentity(),"Y")){
			idAnnotation="@Id " +
					" @GeneratedValue(generator=\"wit-uuid\")" +
					" @GenericGenerator(name=\"wit-uuid\", strategy = \"com.witbyte.core.WitIdentifierGenerator\")";
		}
		StringBuffer columnAnnotation=new StringBuffer(64);
		if(this.getRefEntityName()!=null)
			columnAnnotation.append("\n @ManyToOne @LazyToOne(LazyToOneOption.FALSE)");
		else
			columnAnnotation.append("\n @Column(name=\""+getName()+"\"");
		if(StringUtils.equals(getIsUnique(),"Y")){
			columnAnnotation.append(",unique=true");
		}
		if(StringUtils.equals(getIsNullable(),"Y")){
			columnAnnotation.append(",nullable=true");
		}
		if(getLength()!=0){
			columnAnnotation.append(",length="+getLength());
		}
		if(getJavaTypeName().equals(EntityFieldType.NUMERIC)){
			if(getPrecision()!=0){
				columnAnnotation.append(",precision="+getPrecision());
			}
			if(getScale()!=0){
				columnAnnotation.append(",scale="+getScale());
			}
		}
		columnAnnotation.append(")");
		if(getJavaTypeName().equals(EntityFieldType.DATE)){
			columnAnnotation.append(" @Temporal(TemporalType.DATE)");
		}else if(getJavaTypeName().equals(EntityFieldType.TIME)){
			columnAnnotation.append(" @Temporal(TemporalType.TIME)");
		}else if(getJavaTypeName().equals(EntityFieldType.TIMESTAMP)){
			columnAnnotation.append(" @Temporal(TemporalType.TIMESTAMP)");
		}
		
		
		
		StringBuffer constraints=new StringBuffer();
		
			
		if(getMinLength()!=null){
			constraints.append("@MinLength(length="+getMinLength()+")");
		}
		if(getMaxLength()!=null){
			constraints.append("@MaxLength(length="+getMaxLength()+")");
		}		
		
		if(getJavaTypeName().equals(EntityFieldType.NUMERIC)){
			if(getMaxValue()!=null){
				constraints.append(" @MaxValue("+getMaxValue()+")");
			}
			if(getMinValue()!=null){
				constraints.append(" @Minalue=("+getMinValue()+")");
			}
		}
		if(!StringUtils.equals(getIsNullable(),"Y")){
			constraints.append(" @NotEmpty");
		}
		if(this.getRegularExpression()!=null){
			constraints.append(" @RegularExpression(parent="+this.getRegularExpression()+")");
		}
		if(getJavaTypeName().equals(EntityFieldType.DATE)
						||getJavaTypeName().equals(EntityFieldType.TIME)
						||getJavaTypeName().equals(EntityFieldType.TIMESTAMP))	{
			if(StringUtils.equals(getPast(),"Y")){
				constraints.append(" @DateBefore");
			}else if(StringUtils.equals(getPast(),"Y")){
				constraints.append(" @DateAfter");
			}
		}
		
			
		return idAnnotation+columnAnnotation.toString()+constraints.toString()+getWitAnnotations();
	}	
	public MetaEntity getMetaEntity() {
		return metaEntity;
	}
	public void setMetaEntity(MetaEntity metaEntity) {
		this.metaEntity = metaEntity;
	}
	public MetaEntityField() {
	}
	public MetaEntityField(String name) {
		this(name,EntityFieldType.STRING,name);
	}
	/**
	 * @param name
	 * @param javaType
	 * @param display	
	 */
	public MetaEntityField(String name, String javaTypeName, String display) {
		Assert.isEmpty(name, "类的属性名不能为空。");
		Assert.isEmpty(name, "类的java映射类型不能为空。");
		this.name = name;
		this.typeName = javaTypeName;
		this.displayName = display;		
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}

	public int getLength() {
		return length;
	}
	public void setLength(int length) {
		this.length = length;
	}
	public int getPrecision() {
		return precision_length;
	}
	public void setPrecision(int precision) {
		this.precision_length = precision;
	}
	public int getScale() {
		return scale;
	}
	public void setScale(int scale) {
		this.scale = scale;
	}
	public String getMinLength() {
		return minLength;
	}
	public void setMinLength(String minLength) {
		this.minLength = minLength;
	}
	public String getMaxLength() {
		return maxLength;
	}
	public void setMaxLength(String maxLength) {
		this.maxLength = maxLength;
	}
	public String getMinValue() {
		return minValue;
	}
	public void setMinValue(String minValue) {
		this.minValue = minValue;
	}
	public String getMaxValue() {
		return maxValue;
	}
	public void setMaxValue(String maxValue) {
		this.maxValue = maxValue;
	}

	public int getRangeMin() {
		return rangeMin;
	}
	public void setRangeMin(int rangeMin) {
		this.rangeMin = rangeMin;
	}
	public int getRangeMax() {
		return rangeMax;
	}
	public void setRangeMax(int rangeMax) {
		this.rangeMax = rangeMax;
	}
	public int getSizeMin() {
		return sizeMin;
	}
	public void setSizeMin(int sizeMin) {
		this.sizeMin = sizeMin;
	}
	public int getSizeMax() {
		return sizeMax;
	}
	public void setSizeMax(int sizeMax) {
		this.sizeMax = sizeMax;
	}

	public String getTemporal() {
		return temporal;
	}
	public void setTemporal(String temporal) {
		this.temporal = temporal;
	}
	public String getDisplayName() {
		return displayName;
	}
	public void setDisplayName(String displayName) {
		this.displayName = displayName;
	}
	
	public String getFormat() {
		return format;
	}
	public void setFormat(String format) {
		this.format = format;
	}
	
		
	public int getSortnum() {
		return sortnum;
	}
	public void setSortnum(int sortnum) {
		this.sortnum = sortnum;
	}
	public String getIsIdentity() {
		return isIdentity;
	}
	public void setIsIdentity(String isIdentity) {
		this.isIdentity = isIdentity;
	}
	public String getIsUnique() {
		return isUnique;
	}
	public void setIsUnique(String isUnique) {
		this.isUnique = isUnique;
	}
	public String getIsNullable() {
		return isNullable;
	}
	public void setIsNullable(String isNullable) {
		this.isNullable = isNullable;
	}
	public String getPast() {
		return past;
	}
	public void setPast(String past) {
		this.past = past;
	}
	public String getFuture() {
		return future;
	}
	public void setFuture(String future) {
		this.future = future;
	}
	
	public String getIsparent() {
		return isparent;
	}
	public void setIsparent(String isparent) {
		this.isparent = isparent;
	}
	public String getIsencrypted() {
		return isencrypted;
	}
	public void setIsencrypted(String isencrypted) {
		this.isencrypted = isencrypted;
	}
	public String getIsselectioncolumn() {
		return isselectioncolumn;
	}
	public void setIsselectioncolumn(String isselectioncolumn) {
		this.isselectioncolumn = isselectioncolumn;
	}
	public String getTypeName() {
		return typeName;
	}
	public void setTypeName(String typeName) {
		this.typeName = typeName;
	}
	public String getRefEntityName() {
		return refEntityName;
	}
	public void setRefEntityName(String refEntityName) {
		this.refEntityName = refEntityName;
	}
	public String getRegularExpression() {
		return regularExpression;
	}
	public void setRegularExpression(String regularExpression) {
		this.regularExpression = regularExpression;
	}
	
}
